package com.lanyou.cook.web;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.pentaho.di.core.encryption.Encr;
import org.pentaho.di.core.encryption.KettleTwoWayPasswordEncoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.google.gson.JsonObject;
import com.lanyou.cook.common.Constants;
import com.lanyou.cook.datadictionary.UserLogOpt;
import com.lanyou.cook.entity.domain.DBlink;
import com.lanyou.cook.entity.domain.DBlinkDataSource;
import com.lanyou.cook.entity.domain.DBlinkInterface;
import com.lanyou.cook.entity.domain.FieldSystem;
import com.lanyou.cook.entity.domain.KettleDataSourceEx;
import com.lanyou.cook.repository.DBlinkDataSourceRepository;
import com.lanyou.cook.repository.DBlinkInterfaceRepository;
import com.lanyou.cook.repository.DBlinkRepository;
import com.lanyou.cook.repository.FieldSystemRepository;
import com.lanyou.cook.service.UserLogService;
import com.lanyou.cook.service.security.UserSessionService;
import com.lanyou.cook.util.RSAUtil;
import com.lanyou.cook.web.param.DBlinkParam;

/**
 * 
 * @author 曾族根
 *
 */
@RestController 
@RequestMapping(Constants.BASE_URL_API + "/dBlinks")
public class DBlinkController {
	@Autowired
	private UserSessionService userSessionService;
	@Autowired
	private DBlinkInterfaceRepository dblinkInterfaceRepository;
	@Autowired
	private DBlinkRepository dBlinkManageRepository;
	@Autowired
	private FieldSystemRepository fieldSystemRepository;
	@Autowired
	private UserLogService userLogService;
	@Autowired
	private DBlinkDataSourceRepository  dblinkDataSourceRepository;
	

	/**
	 * 查询带参数条件的dblink
	 * 
	 * @param param
	 *            类型：DBlinkParam
	 * @param pageable
	 *            类型：Pageable
	 * @return 带参数条件下的dblink
	 */
	@RequestMapping("/search/findByExample")
	@RequiresPermissions(value={"dbLinkManagement:view","dbLinkManagement:maintain"},logical=Logical.OR)
	public Page<DBlink> findByExample(DBlinkParam param, Pageable pageable) {
		Specification<DBlink> spec = new Specification<DBlink>() {
			@Override
			public Predicate toPredicate(Root<DBlink> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				List<Predicate> predicatesList = new ArrayList<>();

				// 接口名称
				if (StringUtils.isNotBlank(param.getName())) {
					predicatesList.add(cb.like(root.get("name"), '%' + param.getName() + '%'));
				}

				// 目标用户
				if (StringUtils.isNotBlank(param.getOwnerUser())) {
					predicatesList.add(cb.like(root.get("ownerUser"), '%' + param.getOwnerUser() + '%'));
				}

				// 源主机
				if (StringUtils.isNotBlank(param.getOwnerHost())) {
					predicatesList.add(cb.like(root.get("ownerHost"), '%' + param.getOwnerHost() + '%'));
				}
				// 目标主机
				if (StringUtils.isNotBlank(param.getHost())) {
					predicatesList.add(cb.like(root.get("host"), '%' + param.getHost() + '%'));
				}

				// 服务实例名
				if (StringUtils.isNotBlank(param.getServiceName())) {
					predicatesList.add(cb.like(root.get("serviceName"), '%' + param.getServiceName() + '%'));
				}
				// 源实例名
				if (StringUtils.isNotBlank(param.getOwnerServiceName())) {
					predicatesList.add(cb.like(root.get("ownerServiceName"), '%' + param.getOwnerServiceName() + '%'));
				}

				// 系统
				if (StringUtils.isNotBlank(param.getFieldSystemName())) {
					predicatesList.add(cb.like(root.get("fieldSystem").get("id"), '%' + param.getFieldSystemName() + '%'));
				}else{
					Path<String> pathOwnerFieldSystemId = root.get("fieldSystem").get("id");
					// 默认查当前登录用户所管理的领域系统
					Collection<String> fieldSystemIds = userSessionService.findFieldSystemIdsOfCurrentAuthenticatedUserCanManage();
					if(!CollectionUtils.isEmpty(fieldSystemIds)){
						predicatesList.add(pathOwnerFieldSystemId.in(fieldSystemIds));
					}else {
						predicatesList.add(cb.notEqual(cb.literal(1), 1));
					}
				}
				// 领域
				if (StringUtils.isNotBlank(param.getFieldName())) {
					predicatesList
							.add(cb.like(root.get("fieldSystem").get("field").get("id"), '%' + param.getFieldName() + '%'));
				}

				query.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
				return null;
			}
		};

		return dBlinkManageRepository.findAll(spec, pageable);
	}

	/**
	 * dblink的combobox
	 * 
	 * @return 所有dblink
	 */
	@RequestMapping("/search/findAll")
	public List<DBlink> findAll() {
		Specification<DBlink> spec = new Specification<DBlink>() {
			@Override
			public Predicate toPredicate(Root<DBlink> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				List<Predicate> predicatesList = new ArrayList<>();
					Path<String> pathOwnerFieldSystemId = root.get("fieldSystem").get("id");
					// 默认查当前登录用户所管理的领域系统
					Collection<String> fieldSystemIds = userSessionService.findFieldSystemIdsOfCurrentAuthenticatedUserCanManage();
					if(!CollectionUtils.isEmpty(fieldSystemIds)){
						predicatesList.add(pathOwnerFieldSystemId.in(fieldSystemIds));
					}else {
						predicatesList.add(cb.notEqual(cb.literal(1), 1));
					}
				query.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
				return null;
			}
		};

		return dBlinkManageRepository.findAll(spec);
	}

	/**
	 * 检查dblink是否重名
	 * 
	 * @param name
	 *            类型：String
	 * @param ownerHost
	 *            类型：String
	 * @param originalId
	 *            类型：String
	 * @return 类型:String JSON格式的结果
	 */
	@RequestMapping(value = "/search/checkIsCanSave", produces = "application/json")
	public String checkIsCanSave(String name, String ownerHost, String originalId) {
		DBlink dblink = dBlinkManageRepository.findByNameAndOwnerHost(name, ownerHost);
		if (dblink != null) {
			if (!StringUtils.equals(dblink.getId(), originalId)) {
				JsonObject result = new JsonObject();
				result.addProperty("isCanSave", false);
				result.addProperty("reason", "数据库中已存在，不能保存！");
				return result.toString();
			}
		}

		JsonObject result = new JsonObject();
		result.addProperty("isCanSave", true);
		return result.toString();
	}
	
	
	/**
	 * DBlink新增和修改   2016-4-10 by 曾族根
	 * @param param
	 * @return
	 */
	@RequestMapping(value = "/saveOrUpdate", produces = "application/json", method=RequestMethod.POST)
	@RequiresPermissions(value={"dbLinkManagement:maintain"})
	public String  saveOrUpdate(@RequestBody DBlinkParam param){
		boolean flag = false;
		DBlink dblink = dBlinkManageRepository.findOne(param.getId());
		if(dblink == null){
			dblink = new DBlink();
			flag = true;
		}
		JsonObject result = new JsonObject();
		DBlink dblinks = dBlinkManageRepository.findByNameAndOwnerHost(param.getName(), param.getOwnerHost());
		if (dblinks != null) {
			if (!StringUtils.equals(dblink.getId(), param.getId())) {
				result.addProperty("isCanSave", false);
				result.addProperty("reason", "数据库中已存在，不能保存！");
				return result.toString();
			}
		}
		
		String password =param.getDestUserPassWord() ;
		try {
			// 进行RSA解密
		password = RSAUtil.decryptByPrivateKey(param.getDestUserPassWord(), Constants.PRIVATE_KEY_BASE64);
	    param.setDestUserPassWord(password);
		} catch (Exception e) {

		}

		if(StringUtils.isEmpty(password))
	    throw new RuntimeException("Password is invalid");
		// 原密码未经过加密，则此时加密
		if(!password.startsWith(KettleTwoWayPasswordEncoder.PASSWORD_ENCRYPTED_PREFIX)){
			String encryptedPassword = Encr.encryptPasswordIfNotUsingVariables(password);
			dblink.setDestPassword(encryptedPassword);
			param.setDestUserPassWord(encryptedPassword);
		}
		if(flag){
			// 2016-5-31 新增dblink的同时新增dblink数据库链接  
			if(param.getHost()!=null){
			DBlinkDataSource  dblinkDataSources = new DBlinkDataSource(); 
			dblinkDataSources.setName(param.getName());
			dblinkDataSources.setHost(param.getHost());
			dblinkDataSources.setUser(param.getDestUser());
			dblinkDataSources.setPassword(param.getDestUserPassWord());
			dblinkDataSources.setPort(param.getPort());
			dblinkDataSources.setDbname(param.getServiceName());
			dblinkDataSourceRepository.save(Arrays.asList(dblinkDataSources));
			userLogService.save(UserLogOpt.MaintenanceDataSource, null,
					String.format("新增了dblink数据库链接“%s”的信息", dblink.getName()));
			}
		}else{
			//同步维护领域数据源
			DBlinkDataSource dblinkDataSource = dblinkDataSourceRepository.findByNameAndHost(dblink.getName(), dblink.getHost());
			if(dblinkDataSource!=null){
				dblinkDataSource.setName(param.getName());
				dblinkDataSource.setHost(param.getHost());
				dblinkDataSource.setUser(param.getDestUser());
				dblinkDataSource.setPassword(param.getDestUserPassWord());
				dblinkDataSource.setPort(param.getPort());
				dblinkDataSource.setDbname(param.getServiceName());
				dblinkDataSourceRepository.save(Arrays.asList(dblinkDataSource));
				userLogService.save(UserLogOpt.MaintenanceDataSource, null,
						String.format("修改了dblink数据库链接“%s”的信息", dblinkDataSource.getName()));
			}
			
		}
		// 设置所属领域系统
		FieldSystem fieldSystem = fieldSystemRepository.findOne(FieldSystem.idSpecification(param.getFieldSystemName()));
		dblink.setFieldSystem(fieldSystem);
		//目标账号
		dblink.setDestUserCode(param.getDestUser());
		dblink.setHost(param.getHost());
		dblink.setName(param.getName());
		dblink.setOwnerHost(param.getOwnerHost());
		dblink.setOwnerPort(param.getOwnerPort());
		dblink.setOwnerServiceName(param.getOwnerServiceName());
		dblink.setOwnerUser(param.getOwnerUser());
		dblink.setServiceName(param.getServiceName());
		dblink.setServicePort(param.getPort());
		
		dBlinkManageRepository.save(Arrays.asList(dblink));
		if(flag){
		userLogService.save(UserLogOpt.MaintenanceDBlink, null,
				String.format("新增了dblik“%s”的信息",dblink.getName()));
		}else{
			userLogService.save(UserLogOpt.MaintenanceDBlink, null,
					String.format("修改dblik“%s”的信息",dblink.getName()));
		}
		result.addProperty("errorCode", "SUCCESS");
		String userCode = UserSessionService.getCurrentAuthenticatedUserCode();
		
		return result.toString();
	}
	
	
	
	
	/**
	 * 判断dblink是否可以被删除
	 * 
	 * @param id
	 *            类型:String
	 * @return 类型:String JSON格式的结果
	 */
	@RequestMapping(value = "/search/checkIsCanDelete", produces = "application/json")
	public String checkIsCanDelete(String id) {
		List<DBlinkInterface> dblinkInterface = dblinkInterfaceRepository.findByDblink_Id(id);

		if (!dblinkInterface.isEmpty()) {
			JsonObject result = new JsonObject();
			result.addProperty("isCanDelete", false);
			result.addProperty("reason", "该dblink被引用，不能删除");
			return result.toString();
		} else {
			JsonObject result = new JsonObject();
			result.addProperty("isCanDelete", true);
			return result.toString();
		}
	}

}
